using System;
using System.IO;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace Mars.ShaderAnalysis
{
    public static class EditorGUILayoutUtility
    {
        /// <summary>
        /// 当前退格宽度
        /// </summary>
        public static float indentLevelWidth
        {
            get { return EditorGUI.indentLevel * 15f; }
        }

        /// <summary>
        /// 一个中文字符的宽度
        /// </summary>
        public static float chineseCharactersWidth
        {
            get { return 12f; }
        }

        /// <summary>
        /// 一个控件左右空出的宽度
        /// </summary>
        public static float controllerLeftRightSpaceWidth
        {
            get { return 2f; }
        }

        /// <summary>
        /// materialEditor前面空出的宽度
        /// </summary>
        public static float materialEditorSpaceWidth
        {
            get { return 18f; }
        }

        /// <summary>
        /// 选择对象
        /// </summary>
        public static void PickObjectField<T>(ref T myObj, GUIContent label, bool showPickButton, float buttonWidth = 80f) where T : UnityEngine.Object
        {
            using (new GUILayout.HorizontalScope())
            {
                //显示选中对象
                myObj = EditorGUILayout.ObjectField(label, myObj, typeof(T), true) as T;
                if (showPickButton)
                {
                    //获取当前文件夹
                    if (GUILayout.Button("选择", GUILayout.MaxWidth(buttonWidth)))
                    {
                        var myobject = GetSelectObject<T>();
                        if (myobject != null)
                        {
                            myObj = myobject;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 获取当前选中的Objcet
        /// </summary>
        /// <returns></returns>
        public static T GetSelectObject<T>() where T : UnityEngine.Object
        {
            if (Selection.activeObject == null)
            {
                Debug.Log(1);
                return null;
            }
            else
            {
                return Selection.activeObject as T;
            }
        }

        #region 路径GUI

        /// <summary>
        /// 获取当前选中的文件夹路径
        /// </summary>
        /// <returns></returns>
        public static string GetSelectFolderPath()
        {
            if (Selection.assetGUIDs.Length <= 0)
            {
                return null;
            }

            string guid = Selection.assetGUIDs[0];
            string path = AssetDatabase.GUIDToAssetPath(guid);
            //选中的是文件夹
            if (!string.IsNullOrEmpty(path) && !Path.HasExtension(path))
            {
                return path;
            }

            return null;
        }

        /// <summary>
        /// 显示文件夹路径
        /// </summary>
        public static void FolderPathField(SerializedProperty folderPathSerializedProperty, string label, bool showSelectButton, bool showPickButton, float buttonWidth = 80f)
        {
            FolderPathField(folderPathSerializedProperty, EditorGUIUtility.TrTextContent(label), showSelectButton, showPickButton,
                buttonWidth);
        }

        /// <summary>
        /// 显示文件夹路径
        /// </summary>
        public static void FolderPathField(SerializedProperty folderPathSerializedProperty, GUIContent label, bool showSelectButton, bool showPickButton, float buttonWidth = 80f)
        {
            using (new GUILayout.HorizontalScope())
            {
                //显示选中文件夹
                EditorGUILayout.PropertyField(folderPathSerializedProperty, label);

                if (showSelectButton)
                {
                    //选择文件夹
                    if (GUILayout.Button("Select", GUILayout.MaxWidth(buttonWidth)))
                    {
                        string folderPath =
                            folderPathSerializedProperty.stringValue.Replace("Assets", Application.dataPath);
                        folderPath = EditorUtility.OpenFolderPanel("Select Folder", folderPath, "");
                        folderPath = folderPath.Replace(Application.dataPath, "Assets");
                        if (!string.IsNullOrEmpty(folderPath))
                        {
                            if (folderPathSerializedProperty.stringValue != folderPath)
                            {
                                folderPathSerializedProperty.stringValue = folderPath;
                            }
                        }
                    }
                }

                if (showPickButton)
                {
                    //获取当前文件夹
                    if (GUILayout.Button("Pick", GUILayout.MaxWidth(buttonWidth)))
                    {
                        string folderPath = GetSelectFolderPath();
                        if (!string.IsNullOrEmpty(folderPath))
                        {
                            folderPathSerializedProperty.stringValue = folderPath;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 显示文件夹路径
        /// </summary>
        public static void FolderPathField(ref string folderPath, string label, bool showSelectButton, bool showPickButton, float buttonWidth = 80f)
        {
            FolderPathField(ref folderPath, EditorGUIUtility.TrTextContent(label), showSelectButton, showPickButton, buttonWidth);
        }

        /// <summary>
        /// 显示文件夹路径
        /// </summary>
        public static void FolderPathField(ref string folderPath, GUIContent label, bool showSelectButton, bool showPickButton, float buttonWidth = 80f)
        {
            using (new GUILayout.HorizontalScope())
            {
                //显示选中文件夹
                EditorGUILayout.TextField(label, folderPath);

                if (showSelectButton)
                {
                    //选择文件夹
                    if (GUILayout.Button("Select", GUILayout.MaxWidth(buttonWidth)))
                    {
                        string folderFullPath = folderPath.Replace("Assets", Application.dataPath);
                        folderFullPath = EditorUtility.OpenFolderPanel("Select Folder", folderFullPath, "");
                        folderFullPath = folderFullPath.Replace(Application.dataPath, "Assets");
                        if (!string.IsNullOrEmpty(folderFullPath))
                        {
                            folderPath = folderFullPath;
                            GUI.changed = true;
                        }
                    }
                }

                if (showPickButton)
                {
                    //获取当前文件夹
                    if (GUILayout.Button("Pick", GUILayout.MaxWidth(buttonWidth)))
                    {
                        string selectFolderPath = GetSelectFolderPath();
                        if (!string.IsNullOrEmpty(selectFolderPath))
                        {
                            folderPath = selectFolderPath;
                            GUI.changed = true;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 文件夹路径按钮
        /// </summary>
        public static bool FolderPathButton(string inFolderPath, string projectPath, out string outFolderPath, string guiStyle = "Badge")
        {
            outFolderPath = null;
            if (GUILayout.Button(inFolderPath, guiStyle))
            {
                string path = EditorUtility.OpenFolderPanel("Select Folder", projectPath + inFolderPath, "");
                if (!string.IsNullOrEmpty(path))
                {
                    if (!string.IsNullOrEmpty(projectPath))
                    {
                        path = path.Replace(projectPath, "");
                    }

                    if (inFolderPath != path)
                    {
                        outFolderPath = path;
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// 文件夹路径按钮
        /// </summary>
        public static bool FolderPathButton(string title, string inFolderPath, string projectPath, out string outFolderPath, string guiStyle = "Badge")
        {
            outFolderPath = null;
            Rect rect = EditorGUILayout.GetControlRect(true);
            EditorGUI.PrefixLabel(rect, EditorGUIUtility.TrTextContent(title));
            rect.x += EditorGUIUtility.labelWidth;
            rect.width = (rect.width - EditorGUIUtility.labelWidth) / (EditorGUIUtility.wideMode ? 1f : 2f);
            if (GUI.Button(rect, inFolderPath, guiStyle))
            {
                string path = EditorUtility.OpenFolderPanel("Select Folder", projectPath + inFolderPath, "");
                if (!string.IsNullOrEmpty(path))
                {
                    if (!string.IsNullOrEmpty(projectPath))
                    {
                        path = path.Replace(projectPath, "");
                    }

                    if (inFolderPath != path)
                    {
                        outFolderPath = path;
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// 文件夹路径按钮
        /// </summary>
        public static bool FilePathButton(string inFilePath, string projectPath, out string outFilePath, string guiStyle = "Badge")
        {
            outFilePath = null;
            if (GUILayout.Button(inFilePath, guiStyle))
            {
                string inPath = projectPath + inFilePath;
                int index1 = inPath.LastIndexOf('/');
                int index2 = inPath.LastIndexOf('.');
                string directory = inPath.Remove(index1, inPath.Length - index1);
                string extension = inPath.Remove(0, index2 + 1);
                string defaultName = inPath.Remove(0, index1 + 1).Replace("." + extension, string.Empty);
                string path = EditorUtility.SaveFilePanel("Select File", directory, defaultName, extension);
                if (!string.IsNullOrEmpty(path))
                {
                    if (!string.IsNullOrEmpty(projectPath))
                    {
                        path = path.Replace(projectPath, "");
                    }

                    if (inFilePath != path)
                    {
                        outFilePath = path;
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// 文件夹路径按钮
        /// </summary>
        public static bool FilePathButton(string title, string inFolderPath, string projectPath, out string outFolderPath, string guiStyle = "Badge")
        {
            outFolderPath = null;
            Rect rect = EditorGUILayout.GetControlRect(true);
            EditorGUI.PrefixLabel(rect, EditorGUIUtility.TrTextContent(title));
            rect.x += EditorGUIUtility.labelWidth;
            rect.width = (rect.width - EditorGUIUtility.labelWidth) / (EditorGUIUtility.wideMode ? 1f : 2f);
            if (GUI.Button(rect, inFolderPath, guiStyle))
            {
                string inPath = projectPath + inFolderPath;
                int index1 = inPath.LastIndexOf('/');
                int index2 = inPath.LastIndexOf('.');
                string directory = inPath.Remove(index1, inPath.Length - index1);
                string extension = inPath.Remove(0, index2 + 1);
                string defaultName = inPath.Remove(0, index1 + 1).Replace("." + extension, string.Empty);
                string path = EditorUtility.SaveFilePanel("Select File", directory, defaultName, extension);
                if (!string.IsNullOrEmpty(path))
                {
                    if (!string.IsNullOrEmpty(projectPath))
                    {
                        path = path.Replace(projectPath, "");
                    }

                    if (inFolderPath != path)
                    {
                        outFolderPath = path;
                        return true;
                    }
                }
            }

            return false;
        }

        #endregion

        #region 画线

        public static Color defaultLineColor = new Color(0.12f, 0.12f, 0.12f, 1.333f);

        /// <summary>
        /// 绘制线条
        /// </summary>
        public static void DrawLine(float left = 0f, float right = 0f, float height = 1)
        {
            DrawLine(defaultLineColor, left, right, height);
        }

        /// <summary>
        /// 绘制线条
        /// </summary>
        public static void DrawLine(Color color, float left = 0f, float right = 0f, float height = 1)
        {
            Rect rect = EditorGUILayout.GetControlRect(false, height);
            rect.xMin += left;
            rect.xMax -= right;
            EditorGUI.DrawRect(rect, color);
        }

        #endregion

        #region 最大最小值滑动条

        public static void MinMaxSliderField(GUIContent title, SerializedProperty prop, float min, float max)
        {
            Vector2 v = prop.vector2Value;
            const int kFloatFieldWidth = 50;
            const int kSeparatorWidth = 5;
            float indentOffset = EditorGUI.indentLevel * 15f;
            var lineRect = GUILayoutUtility.GetRect(1, EditorGUIUtility.singleLineHeight);
            lineRect.xMin += 4f;
            lineRect.y += 2f;
            var labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset,
                lineRect.height);
            var floatFieldLeft = new Rect(labelRect.xMax, lineRect.y, kFloatFieldWidth + indentOffset, lineRect.height);
            var sliderRect = new Rect(floatFieldLeft.xMax + kSeparatorWidth - indentOffset, lineRect.y,
                lineRect.width - labelRect.width - kFloatFieldWidth * 2 - kSeparatorWidth * 2, lineRect.height);
            var floatFieldRight = new Rect(sliderRect.xMax + kSeparatorWidth - indentOffset, lineRect.y,
                kFloatFieldWidth + indentOffset, lineRect.height);

            EditorGUI.PrefixLabel(labelRect, title);
            v.x = EditorGUI.FloatField(floatFieldLeft, v.x);
            EditorGUI.MinMaxSlider(sliderRect, ref v.x, ref v.y, min, max);
            v.y = EditorGUI.FloatField(floatFieldRight, v.y);
            if (v.x >= v.y)
            {
                v.y = v.x + 0.001f;
            }

            prop.vector2Value = v;
        }

        public static void MinMaxSliderField(GUIContent title, MaterialProperty prop, float min, float max)
        {
            Vector2 v = prop.vectorValue;
            const int kFloatFieldWidth = 50;
            const int kSeparatorWidth = 5;
            float indentOffset = EditorGUI.indentLevel * 15f;
            var lineRect = GUILayoutUtility.GetRect(1, EditorGUIUtility.singleLineHeight);
            lineRect.xMin += 4f;
            lineRect.y += 2f;
            var labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset,
                lineRect.height);
            var floatFieldLeft = new Rect(labelRect.xMax, lineRect.y, kFloatFieldWidth + indentOffset, lineRect.height);
            var sliderRect = new Rect(floatFieldLeft.xMax + kSeparatorWidth - indentOffset, lineRect.y,
                lineRect.width - labelRect.width - kFloatFieldWidth * 2 - kSeparatorWidth * 2, lineRect.height);
            var floatFieldRight = new Rect(sliderRect.xMax + kSeparatorWidth - indentOffset, lineRect.y,
                kFloatFieldWidth + indentOffset, lineRect.height);

            EditorGUI.PrefixLabel(labelRect, title);
            v.x = EditorGUI.FloatField(floatFieldLeft, v.x);
            EditorGUI.MinMaxSlider(sliderRect, ref v.x, ref v.y, min, max);
            v.y = EditorGUI.FloatField(floatFieldRight, v.y);
            if (v.x >= v.y)
            {
                v.y = v.x + 0.001f;
            }

            prop.vectorValue = v;
        }

        public static void MinMaxSliderField(GUIContent title, SerializedProperty propX, SerializedProperty propY,
            float min, float max)
        {
            const int kFloatFieldWidth = 50;
            const int kSeparatorWidth = 5;
            float indentOffset = EditorGUI.indentLevel * 15f;
            var lineRect = GUILayoutUtility.GetRect(1, EditorGUIUtility.singleLineHeight);
            lineRect.xMin += 4f;
            lineRect.y += 2f;
            var labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset,
                lineRect.height);
            var floatFieldLeft = new Rect(labelRect.xMax, lineRect.y, kFloatFieldWidth + indentOffset, lineRect.height);
            var sliderRect = new Rect(floatFieldLeft.xMax + kSeparatorWidth - indentOffset, lineRect.y,
                lineRect.width - labelRect.width - kFloatFieldWidth * 2 - kSeparatorWidth * 2, lineRect.height);
            var floatFieldRight = new Rect(sliderRect.xMax + kSeparatorWidth - indentOffset, lineRect.y,
                kFloatFieldWidth + indentOffset, lineRect.height);

            EditorGUI.PrefixLabel(labelRect, title);
            float x = propX.floatValue;
            float y = propY.floatValue;
            x = EditorGUI.FloatField(floatFieldLeft, x);
            EditorGUI.MinMaxSlider(sliderRect, ref x, ref y, min, max);
            y = EditorGUI.FloatField(floatFieldRight, y);
            if (x >= y)
            {
                y = x + 0.001f;
            }

            propX.floatValue = x;
            propY.floatValue = y;
        }

        public static void MinMaxSliderField(GUIContent title, MaterialProperty propX, MaterialProperty propY,
            float min, float max)
        {
            const int kFloatFieldWidth = 50;
            const int kSeparatorWidth = 5;
            float indentOffset = EditorGUI.indentLevel * 15f;
            var lineRect = GUILayoutUtility.GetRect(1, EditorGUIUtility.singleLineHeight);
            lineRect.xMin += 4f;
            lineRect.y += 2f;
            var labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset,
                lineRect.height);
            var floatFieldLeft = new Rect(labelRect.xMax, lineRect.y, kFloatFieldWidth + indentOffset, lineRect.height);
            var sliderRect = new Rect(floatFieldLeft.xMax + kSeparatorWidth - indentOffset, lineRect.y,
                lineRect.width - labelRect.width - kFloatFieldWidth * 2 - kSeparatorWidth * 2, lineRect.height);
            var floatFieldRight = new Rect(sliderRect.xMax + kSeparatorWidth - indentOffset, lineRect.y,
                kFloatFieldWidth + indentOffset, lineRect.height);

            EditorGUI.PrefixLabel(labelRect, title);
            float x = propX.floatValue;
            float y = propY.floatValue;
            x = EditorGUI.FloatField(floatFieldLeft, x);
            EditorGUI.MinMaxSlider(sliderRect, ref x, ref y, min, max);
            y = EditorGUI.FloatField(floatFieldRight, y);
            if (x >= y)
            {
                y = x + 0.001f;
            }

            propX.floatValue = x;
            propY.floatValue = y;
        }

        #endregion

        #region Scope

        /// <summary>
        /// 四周带空位的HorizontalScope
        /// </summary>
        public class HorizontalScopeWithSpace : GUI.Scope
        {
            private float spaceLeft = 0f;
            private float spaceUp = 0f;
            private float spaceRight = 0f;
            private float spaceDown = 0f;

            public HorizontalScopeWithSpace(float space, params GUILayoutOption[] options)
            {
                OpenScope(space);
                GUILayout.BeginHorizontal(options);
            }

            public HorizontalScopeWithSpace(float space, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(space);
                GUILayout.BeginHorizontal(style, options);
            }

            public HorizontalScopeWithSpace(float space, string text, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(space);
                GUILayout.BeginHorizontal(text, style, options);
            }

            public HorizontalScopeWithSpace(float space, Texture image, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(space);
                GUILayout.BeginHorizontal(image, style, options);
            }

            public HorizontalScopeWithSpace(float space, GUIContent content, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(space);
                GUILayout.BeginHorizontal(content, style, options);
            }

            public HorizontalScopeWithSpace(float spaceX, float spaceY, params GUILayoutOption[] options)
            {
                OpenScope(spaceX, spaceY);
                GUILayout.BeginHorizontal(options);
            }

            public HorizontalScopeWithSpace(float spaceX, float spaceY, GUIStyle style,
                params GUILayoutOption[] options)
            {
                OpenScope(spaceX, spaceY);
                GUILayout.BeginHorizontal(style, options);
            }

            public HorizontalScopeWithSpace(float spaceX, float spaceY, string text, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(spaceX, spaceY);
                GUILayout.BeginHorizontal(text, style, options);
            }

            public HorizontalScopeWithSpace(float spaceX, float spaceY, Texture image, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(spaceX, spaceY);
                GUILayout.BeginHorizontal(image, style, options);
            }

            public HorizontalScopeWithSpace(float spaceX, float spaceY, GUIContent content, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(spaceX, spaceY);
                GUILayout.BeginHorizontal(content, style, options);
            }

            public HorizontalScopeWithSpace(float left, float right, float up, float down, params GUILayoutOption[] options)
            {
                OpenScope(left, right, up, down);
                GUILayout.BeginHorizontal(options);
            }

            public HorizontalScopeWithSpace(float left, float right, float up, float down, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(left, right, up, down);
                GUILayout.BeginHorizontal(style, options);
            }

            public HorizontalScopeWithSpace(float left, float right, float up, float down, string text, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(left, right, up, down);
                GUILayout.BeginHorizontal(text, style, options);
            }

            public HorizontalScopeWithSpace(float left, float right, float up, float down, Texture image, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(left, right, up, down);
                GUILayout.BeginHorizontal(image, style, options);
            }

            public HorizontalScopeWithSpace(float left, float right, float up, float down, GUIContent content, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(left, right, up, down);
                GUILayout.BeginHorizontal(content, style, options);
            }

            private void OpenScope(float size)
            {
                OpenScope(size, size, size, size);
            }

            private void OpenScope(float x, float y)
            {
                OpenScope(x, x, y, y);
            }

            private void OpenScope(float left, float right, float up, float down)
            {
                spaceLeft = left;
                spaceRight = right;
                spaceUp = up;
                spaceDown = down;
                GUILayout.BeginVertical();
                GUILayout.Space(spaceUp);
                GUILayout.BeginHorizontal();
                GUILayout.Space(spaceLeft);
            }

            protected override void CloseScope()
            {
                GUILayout.EndHorizontal();
                GUILayout.Space(spaceRight);
                GUILayout.EndHorizontal();
                GUILayout.Space(spaceDown);
                GUILayout.EndVertical();
            }
        }

        /// <summary>
        /// 四周带空位的VerticalScope
        /// </summary>
        public class VerticalScopeWithSpace : GUI.Scope
        {
            private float spaceLeft = 0f;
            private float spaceUp = 0f;
            private float spaceRight = 0f;
            private float spaceDown = 0f;

            public VerticalScopeWithSpace(float space, params GUILayoutOption[] options)
            {
                OpenScope(space);
                GUILayout.BeginVertical(options);
            }

            public VerticalScopeWithSpace(float space, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(space);
                GUILayout.BeginVertical(style, options);
            }

            public VerticalScopeWithSpace(float space, string text, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(space);
                GUILayout.BeginVertical(text, style, options);
            }

            public VerticalScopeWithSpace(float space, Texture image, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(space);
                GUILayout.BeginVertical(image, style, options);
            }

            public VerticalScopeWithSpace(float space, GUIContent content, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(space);
                GUILayout.BeginVertical(content, style, options);
            }

            public VerticalScopeWithSpace(float spaceX, float spaceY, params GUILayoutOption[] options)
            {
                OpenScope(spaceX, spaceY);
                GUILayout.BeginVertical(options);
            }

            public VerticalScopeWithSpace(float spaceX, float spaceY, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(spaceX, spaceY);
                GUILayout.BeginVertical(style, options);
            }

            public VerticalScopeWithSpace(float spaceX, float spaceY, string text, GUIStyle style,
                params GUILayoutOption[] options)
            {
                OpenScope(spaceX, spaceY);
                GUILayout.BeginVertical(text, style, options);
            }

            public VerticalScopeWithSpace(float spaceX, float spaceY, Texture image, GUIStyle style,
                params GUILayoutOption[] options)
            {
                OpenScope(spaceX, spaceY);
                GUILayout.BeginVertical(image, style, options);
            }

            public VerticalScopeWithSpace(float spaceX, float spaceY, GUIContent content, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(spaceX, spaceY);
                GUILayout.BeginVertical(content, style, options);
            }

            public VerticalScopeWithSpace(float left, float right, float up, float down, params GUILayoutOption[] options)
            {
                OpenScope(left, right, up, down);
                GUILayout.BeginVertical(options);
            }

            public VerticalScopeWithSpace(float left, float right, float up, float down, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(left, right, up, down);
                GUILayout.BeginVertical(style, options);
            }

            public VerticalScopeWithSpace(float left, float right, float up, float down, string text, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(left, right, up, down);
                GUILayout.BeginVertical(text, style, options);
            }

            public VerticalScopeWithSpace(float left, float right, float up, float down, Texture image, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(left, right, up, down);
                GUILayout.BeginVertical(image, style, options);
            }

            public VerticalScopeWithSpace(float left, float right, float up, float down, GUIContent content, GUIStyle style, params GUILayoutOption[] options)
            {
                OpenScope(left, right, up, down);
                GUILayout.BeginVertical(content, style, options);
            }

            private void OpenScope(float size)
            {
                OpenScope(size, size, size, size);
            }

            private void OpenScope(float x, float y)
            {
                OpenScope(x, x, y, y);
            }

            private void OpenScope(float left, float right, float up, float down)
            {
                spaceLeft = left;
                spaceRight = right;
                spaceUp = up;
                spaceDown = down;
                GUILayout.BeginVertical();
                GUILayout.Space(spaceUp);
                GUILayout.BeginHorizontal();
                GUILayout.Space(spaceLeft);
            }

            protected override void CloseScope()
            {
                GUILayout.EndVertical();
                GUILayout.Space(spaceRight);
                GUILayout.EndHorizontal();
                GUILayout.Space(spaceDown);
                GUILayout.EndVertical();
            }
        }

        /// <summary>
        /// 自动检查序列化属性变化的Scope
        /// </summary>
        public class SerializedObjectChangeCheckScope : GUI.Scope
        {
            private SerializedObject serializedObject;
            private Action changeCallback;

            public SerializedObjectChangeCheckScope(SerializedObject serializedObject, Action changeCallback = null)
            {
                if (serializedObject != null && serializedObject.targetObject != null)
                {
                    this.serializedObject = serializedObject;
                    this.changeCallback = changeCallback;
                    serializedObject.Update();
                }

                EditorGUI.BeginChangeCheck();
            }

            protected override void CloseScope()
            {
                if (EditorGUI.EndChangeCheck())
                {
                    if (serializedObject != null && serializedObject.targetObject != null)
                    {
                        serializedObject.ApplyModifiedProperties();
                        if (changeCallback != null)
                        {
                            changeCallback();
                        }
                    }
                }
            }
        }

        public class MaterialEditorDefaultGUIWidthsScope : GUI.Scope
        {
            private float fieldWidth;
            private float labelWidth;

            public MaterialEditorDefaultGUIWidthsScope(MaterialEditor materialEditor)
            {
                fieldWidth = EditorGUIUtility.fieldWidth;
                labelWidth = EditorGUIUtility.labelWidth;
                materialEditor.SetDefaultGUIWidths();
            }

            protected override void CloseScope()
            {
                EditorGUIUtility.fieldWidth = fieldWidth;
                EditorGUIUtility.labelWidth = labelWidth;
            }
        }

        public class LabelWidthsScope : GUI.Scope
        {
            private float labelWidth;

            public LabelWidthsScope(float width)
            {
                labelWidth = EditorGUIUtility.labelWidth;
                EditorGUIUtility.labelWidth = width;
            }

            protected override void CloseScope()
            {
                EditorGUIUtility.labelWidth = labelWidth;
            }
        }

        public class GUIColorScope : GUI.Scope
        {
            private Color guiColor;

            public GUIColorScope(Color color)
            {
                guiColor = GUI.color;
                GUI.color = color;
            }

            protected override void CloseScope()
            {
                GUI.color = guiColor;
            }
        }

        #endregion

        /// <summary>
        /// 大数显示
        /// </summary>
        public static string LargeNumberToString(ulong number)
        {
            string numberString = number.ToString();
            string newNumberString = "";
            int index = 0;
            for (int i = numberString.Length - 1; i >= 0; i--)
            {
                index++;
                newNumberString = numberString[i] + newNumberString;
                if (index % 3 == 0 && i > 0)
                {
                    newNumberString = "," + newNumberString;
                    index = 0;
                }
            }

            return newNumberString;
        }

        /// <summary>
        /// 显示文本，并返回文本后的Rect
        /// </summary>
        public static Rect GetAfterLabelRect(string label = null, float height = -1f)
        {
            GUIContent guiContent = null;
            if (!string.IsNullOrEmpty(label))
            {
                guiContent = EditorGUIUtility.TrTextContent(label);
            }

            return GetAfterLabelRect(guiContent, height);
        }

        /// <summary>
        /// 显示文本，并返回文本后的Rect
        /// </summary>
        public static Rect GetAfterLabelRect(GUIContent guiContent = null, float height = -1f)
        {
            if (height <= 0f)
            {
                height = EditorGUIUtility.singleLineHeight;
            }

            Rect rect;
            if (guiContent != null || guiContent == GUIContent.none)
            {
                Rect controlRect = EditorGUILayout.GetControlRect(true, height);
                rect = EditorGUI.PrefixLabel(controlRect, guiContent);
                rect.x -= indentLevelWidth;
                rect.width += indentLevelWidth;
            }
            else
            {
                rect = EditorGUILayout.GetControlRect(false, height);
            }

            return rect;
        }

        #region Vector向量显示

        /// <summary>
        /// 向量V2显示
        /// </summary>
        public static void Vector2PropertyField(SerializedProperty serializedProperty, string label)
        {
            Rect rect = GetAfterLabelRect(label);
            serializedProperty.vector2Value = EditorGUI.Vector2Field(rect, GUIContent.none, serializedProperty.vector2Value);
        }

        /// <summary>
        /// 向量V2显示
        /// </summary>
        public static void Vector2PropertyField(MaterialProperty materialProperty, string label)
        {
            Rect rect = GetAfterLabelRect(label);
            materialProperty.vectorValue = EditorGUI.Vector2Field(rect, GUIContent.none, materialProperty.vectorValue);
        }

        /// <summary>
        /// 向量V2显示
        /// </summary>
        public static Vector2 Vector2PropertyField(Vector2 v2, string label)
        {
            Rect rect = GetAfterLabelRect(label);
            return EditorGUI.Vector2Field(rect, GUIContent.none, v2);
        }

        /// <summary>
        /// 向量V3显示
        /// </summary>
        public static void Vector3PropertyField(SerializedProperty serializedProperty, string label)
        {
            Rect rect = GetAfterLabelRect(label);
            serializedProperty.vector3Value = EditorGUI.Vector3Field(rect, GUIContent.none, serializedProperty.vector3Value);
        }

        /// <summary>
        /// 向量V3显示
        /// </summary>
        public static void Vector3PropertyField(MaterialProperty materialProperty, string label)
        {
            Rect rect = GetAfterLabelRect(label);
            materialProperty.vectorValue = EditorGUI.Vector3Field(rect, GUIContent.none, materialProperty.vectorValue);
        }

        /// <summary>
        /// 向量V3显示
        /// </summary>
        public static Vector3 Vector3PropertyField(Vector3 v3, string label)
        {
            Rect rect = GetAfterLabelRect(label);
            return EditorGUI.Vector3Field(rect, GUIContent.none, v3);
        }

        /// <summary>
        /// 向量V4显示
        /// </summary>
        public static void Vector4PropertyField(SerializedProperty serializedProperty, string label)
        {
            Rect rect = GetAfterLabelRect(label);
            serializedProperty.vector4Value = EditorGUI.Vector4Field(rect, GUIContent.none, serializedProperty.vector4Value);
        }

        /// <summary>
        /// 向量V4显示
        /// </summary>
        public static void Vector4PropertyField(MaterialProperty materialProperty, string label)
        {
            Rect rect = GetAfterLabelRect(label);
            materialProperty.vectorValue = EditorGUI.Vector4Field(rect, GUIContent.none, materialProperty.vectorValue);
        }

        /// <summary>
        /// 向量V4显示
        /// </summary>
        public static Vector4 Vector4PropertyField(Vector4 v4, string label)
        {
            Rect rect = GetAfterLabelRect(label);
            return EditorGUI.Vector4Field(rect, GUIContent.none, v4);
        }

        #endregion

        #region Style折叠菜单栏

        /// <summary>
        /// 立体折叠菜单
        /// </summary>
        private static Texture2D CreateTex(int width, int height, Color col)
        {
            Color[] pix = new Color[width * height];

            for (int i = 0; i < pix.Length; i++)
                pix[i] = col;

            Texture2D result = new Texture2D(width, height);
            result.SetPixels(pix);
            result.Apply();

            return result;
        }

        public static GUIStyle FontStyle(Color myColor, int fontStyle = 1, int alignment = 4, int myfontsize = 12)
        {
            GUIStyle titleStyle = new GUIStyle();
            titleStyle.alignment = (TextAnchor)alignment;
            titleStyle.fontStyle = (FontStyle)fontStyle;
            titleStyle.normal.textColor = myColor;
            titleStyle.fontSize = myfontsize;
            return titleStyle;
        }

        public static void InitializeStyles(Texture2D ButtonTex, GUIStyle buttonStyle, GUIStyle helpBoxStyle,
            GUIStyle notesLabelStyleFade, GUIStyle notesLabelStyle)
        {
            buttonStyle = new GUIStyle();
            buttonStyle.overflow.left = buttonStyle.overflow.right = 3;
            buttonStyle.overflow.top = 2;
            buttonStyle.overflow.bottom = 0;
            if (ButtonTex == null)
            {
                if (EditorGUIUtility.isProSkin)
                    ButtonTex = CreateTex(32, 32, new Color(80 / 255f, 80 / 255f, 80 / 255f));
                else ButtonTex = CreateTex(32, 32, new Color(171 / 255f, 171 / 255f, 171 / 255f));
            }

            buttonStyle.normal.background = ButtonTex;

            helpBoxStyle = new GUIStyle("button");
            helpBoxStyle.alignment = TextAnchor.MiddleCenter;
            helpBoxStyle.stretchHeight = false;
            helpBoxStyle.stretchWidth = false;

            notesLabelStyleFade = new GUIStyle("label");
            notesLabelStyleFade.normal.textColor = EditorGUIUtility.isProSkin
                ? new Color(0.75f, 0.75f, 0.75f, 0.5f)
                : new Color(0.1f, 0.1f, 0.1f, 0.3f);

            notesLabelStyle = new GUIStyle("label");
            notesLabelStyle.normal.textColor = EditorGUIUtility.isProSkin
                ? new Color(0.85f, 0.25f, 0.25f, 0.95f)
                : new Color(0.7f, 0.1f, 0.1f, 0.95f);
        }

        #endregion

        #region 绘制线

        private static void DrawFactorLine(float percentage, Color? color = null, float width = 2.0f)
        {
            Rect rect = GUILayoutUtility.GetLastRect();
            float markerXPos = rect.x + EditorGUIUtility.labelWidth + (rect.width - EditorGUIUtility.labelWidth) * percentage;
            EditorGUI.DrawRect(new Rect(markerXPos, rect.y, width, EditorGUIUtility.singleLineHeight), color ?? Color.yellow);
        }

        public static void PropertyFieldWithLine(SerializedProperty serializedProperty, GUIContent label, float factor)
        {
            EditorGUILayout.PropertyField(serializedProperty, label);
            DrawFactorLine(factor);
        }

        #endregion

        #region 存储开关状态

        /// <summary>
        /// 存储开关状态
        /// </summary>
        public static bool GetFoldoutState(string editorPrefKey, string name)
        {
            // Get value from EditorPrefs
            return EditorPrefs.GetBool($"{editorPrefKey}.{name}");
        }

        public static void SetFoldoutState(string editorPrefKey, string name, bool field, bool value)
        {
            if (field == value)
                return;

            // Set value to EditorPrefs and field
            EditorPrefs.SetBool($"{editorPrefKey}.{name}", value);
        }

        #endregion

        /// <summary>
        /// 打开取色板
        /// </summary>
        public static void ShowColorPicker(Action<Color> colorChangedCallback, Color col, bool showAlpha = true, bool hdr = false)
        {
            Assembly assembly = Assembly.Load("UnityEditor.CoreModule");
            Type type = assembly.GetType("UnityEditor.ColorPicker");
            MethodInfo method = type.GetMethod("Show",
                new Type[] { colorChangedCallback.GetType(), col.GetType(), showAlpha.GetType(), hdr.GetType() });
            method.Invoke(null, new object[] { colorChangedCallback, col, showAlpha, hdr });
        }
    }
}